package com.me.study.ui.activity

import android.Manifest
import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.pm.PackageManager
import android.database.Cursor
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.util.Size
import android.view.View
import android.widget.Toast
import androidx.camera.core.*
import androidx.camera.extensions.ExtensionsManager
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.*
import androidx.camera.video.VideoCapture
import androidx.concurrent.futures.await
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.ToastUtils
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.google.common.util.concurrent.ListenableFuture
import com.gyf.immersionbar.BarHide
import com.gyf.immersionbar.ktx.immersionBar
import com.me.study.R
import com.me.study.app.base.BaseActivity
import com.me.study.app.cameraX.*
import com.me.study.databinding.ActivityCameraXactivityBinding
import com.permissionx.guolindev.PermissionX
import kotlinx.coroutines.launch
import me.hgj.jetpackmvvm.base.viewmodel.BaseViewModel
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt

class CameraXActivity : BaseActivity<BaseViewModel, ActivityCameraXactivityBinding>(),
    PopWin.OnPopCheckListener, RatioPop.OnRatioViewListener, TopView.OnTopViewListener,
    RecordButton.RecordStateListener, RecordCountDownView.OnCountDownListener,
    CameraTabView.OnTabSelectedListener, LoaderManager.LoaderCallbacks<Any>,
    TranslateView.OnTranslateTouchListener, CameraPreView.OnCameraPreViewListener {

    private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
    private var cameraProvider: ProcessCameraProvider? = null
    private var cameraParams: CameraParams? = null
    private var mPreView: Preview? = null
    private var imageCapture: ImageCapture? = null
    private var videoCapture: VideoCapture<Recorder>? = null
    private var cameraControl: CameraControl? = null
    private var camera: Camera? = null
    private var isInt: Boolean = false
    private var isTakePicture: Boolean = true // 是否是拍照
    private var recording: Recording? = null
    private var loaderManager: LoaderManager? = null
    private var zoomCoefficient: Float = 0.1f//缩放系数

    init {
        cameraParams = CameraParams.getInstance(this@CameraXActivity)
    }

    companion object {
        val TAG: String = this::class.java.simpleName
    }

    override fun initImmersionBar() {
        immersionBar {
            statusBarColor(R.color.transparent)
            navigationBarColor(R.color.transparent)
            hideBar(BarHide.FLAG_HIDE_BAR)
        }
    }

    override fun layoutId() = R.layout.activity_camera_xactivity

    override fun initView(savedInstanceState: Bundle?) {
        requestPermission()
    }

    private fun requestPermission() {
        PermissionX.init(this)
            .permissions(
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
            .request { allGranted, grantedList, deniedList ->
                if (allGranted) {
                    openCameraPreView()
                    initLoadManager()
                    mDatabind.cameraTab.addTab(mDatabind.cameraTab.newTab().setText("拍照"))
                    mDatabind.cameraTab.addTab(mDatabind.cameraTab.newTab().setText("录像"))
                    mDatabind.cameraTab.setIndicateCenter(true)
                    mDatabind.cameraTab.setScrollAutoSelected(true)
                    mDatabind.cameraTab.addOnTabSelectedListener(this)
                    mDatabind.top.setOnPopCheckListener(this)
                    mDatabind.top.setOnRatioViewListener(this)
                    mDatabind.top.setOnTopViewListener(this)
                    mDatabind.recordCount.addOnCountDownListener(this)
                    mDatabind.btnRecord.addRecordStateListener(this)
                    mDatabind.translateView.setOnTranslateTouchListener(this)
                    mDatabind.cameraPreview.setOnCameraPreViewListener(this)
                } else {

                }
            }
    }

    /**
     * 打开相机预览
     */
    @SuppressLint("RestrictedApi")
    private fun openCameraPreView() {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this@CameraXActivity)
        cameraProviderFuture?.addListener({
            cameraProvider = cameraProviderFuture?.get()
            if (cameraParams?.mRatioType == CameraRatioType.RATIO_1_1 || cameraParams?.mRatioType == CameraRatioType.RATIO_FULL) {
                val size = if (cameraParams?.mRatioType == CameraRatioType.RATIO_1_1) {
                    Size(ScreenUtils.getScreenWidth() * 2, ScreenUtils.getScreenWidth() * 2)
                } else {
                    Size(ScreenUtils.getScreenWidth() * 2, ScreenUtils.getScreenHeight() * 2)
                }
                // Preview 预览流
                mPreView = Preview.Builder()
                    //设置分辨率
                    .setTargetResolution(size)
                    .build()
                    .also {
                        it.setSurfaceProvider(mDatabind.viewFinder?.surfaceProvider)
                    }
                //图像捕捉
                imageCapture = ImageCapture.Builder()
                    .setTargetResolution(
                        size
                    )
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
                    .build()
            } else {
                // Preview 预览流
                mPreView = Preview.Builder()
                    //设置分辨率
                    .setTargetAspectRatio(cameraParams?.mRatioType!!)
                    .build()
                    .also {
                        it.setSurfaceProvider(mDatabind.viewFinder?.surfaceProvider)
                    }

                //图像捕捉
                imageCapture = ImageCapture.Builder()
                    .setTargetAspectRatio(cameraParams?.mRatioType!!)
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
                    .build()

                LogUtils.d("cameraParams_mRatioType_1" + cameraParams?.mRatioType)

            }


            //闪光灯模式
            val flashMode =
                if (cameraParams?.mSplashOn == true && cameraParams?.mFacingFront == false) {
                    ImageCapture.FLASH_MODE_ON
                } else {
                    ImageCapture.FLASH_MODE_OFF
                }
            imageCapture?.flashMode = flashMode
            //视频帧捕捉
            val recorder = Recorder.Builder()
                .setQualitySelector(
                    QualitySelector.from(
                        Quality.HIGHEST,
                        //设置分辨率
                        FallbackStrategy.higherQualityOrLowerThan(Quality.HIGHEST)
                    )
                )
                .build()
            videoCapture = VideoCapture.withOutput(recorder)


//            val imageAnalysis = ImageAnalysis.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3)
//                .build()


            // 前后置摄像头选择器
            val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(if (cameraParams?.mFacingFront == true) CameraSelector.LENS_FACING_FRONT else CameraSelector.LENS_FACING_BACK)
                .build()
//                //---------------------------------------------CameraX 高级用法 几乎国内设备都不支持扩展-------------------------------------
            var startPreView = false

            lifecycleScope?.launch {
                val extensionsManager =
                    ExtensionsManager.getInstanceAsync(this@CameraXActivity, cameraProvider!!)
                        .await()
                if (extensionsManager.isExtensionAvailable(
                        cameraSelector,
                        cameraParams?.extensionMode!!
                    )
                ) {
                    Log.d(TAG, "支持" + cameraParams?.extensionMode)
                    val extensionId = extensionsManager.getExtensionEnabledCameraSelector(
                        cameraSelector,
                        cameraParams?.extensionMode!!
                    )
                    startPreView = true
                    bindCameraId(extensionId)

                } else {
                    startPreView = false
                    Log.d(TAG, "不支持" + cameraParams?.extensionMode)
                }
            }
            //----------------------------------------------普通绑定---------------------------------------
            if (!startPreView) {
                bindCameraId(cameraSelector)
            }
        }, ContextCompat.getMainExecutor(this@CameraXActivity))
    }

    private fun initLoadManager() {
        loaderManager = LoaderManager.getInstance(this)
        loaderManager?.initLoader(1, null, this)
    }

    /**
     * 绑定相机id
     */
    private fun bindCameraId(cameraSelector: CameraSelector) {
        try {

            cameraProvider?.unbindAll()
            // 绑定输出
            camera = cameraProvider?.bindToLifecycle(
                this@CameraXActivity,
                cameraSelector,
                mPreView,
                imageCapture,
                videoCapture

            )
            if (!isInt) {
                isInt = true
                ratioCallBack(cameraParams?.mRatioType)
            }
            cameraControl = camera?.cameraControl

            focus(
                mDatabind.viewFinder.width.div(2f),
                mDatabind.viewFinder.height.div(2f),
                true
            )


        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
    }

    private fun ratioCallBack(ratio: Int?) {
        ratio?.let {
            var bottom = 0
            var top = 0
            val screenWidth = ScreenUtils.getScreenWidth()
            val screenHeight = ScreenUtils.getScreenHeight()


            when (it) {

                CameraRatioType.RATIO_3_4 -> {
                    val height = screenWidth.div(3f / 4f).toInt()
                    val value = screenHeight - height
                    top = (value * (1f.div(3f))).roundToInt()
                    bottom = (value * (2f.div(3f))).roundToInt()

                    Log.d("TAG", "value=$value")
                    Log.d(
                        "TAG",
                        "top=" + top + "bottom=" + bottom + "1f.div(3f)" + 1f.div(3f).toInt()
                    )

                }
                CameraRatioType.RATIO_9_16 -> {
                    val height = screenWidth.div(9f / 16f).roundToInt()
                    top = 0
                    bottom = screenHeight - height
                }
                CameraRatioType.RATIO_1_1 -> {
                    top = (screenHeight - screenWidth).div(2f).roundToInt()
                    bottom = top
                }
                CameraRatioType.RATIO_FULL -> {
                    top = 0
                    bottom = 0
                }
                else -> {
                    val height = screenWidth.div(3f / 4f).roundToInt()
                    val value = screenHeight - height
                    top = value * (1f.div(3f)).roundToInt()
                    bottom = value * (2f.div(3f)).roundToInt()
                }
            }
            val centerHeight = screenHeight - (top + bottom)
            mDatabind.cameraPreview.setHTop(top)
            mDatabind.autoTop.startTranslate(top, it)
            mDatabind.autoBottom.startTranslate(bottom, it)

        }
    }

    /**
     * 录像
     */
    @SuppressLint("CheckResult")
    private fun takeVideo() {
        val videoCapture = this.videoCapture ?: return


        //如果正在录制，则停止
        if (recording != null) {
            recording?.stop()
            recording = null
            return
        }

        val name = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
            .format(System.currentTimeMillis())
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
            put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video")
            }
        }

        val mediaStoreOutputOptions = this.contentResolver?.let {
            MediaStoreOutputOptions
                .Builder(it, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
                .setContentValues(contentValues)
                .build()
        }
        recording = videoCapture.output
            .prepareRecording(this@CameraXActivity, mediaStoreOutputOptions!!)
            .apply {
                if (ActivityCompat.checkSelfPermission(
                        this@CameraXActivity,
                        Manifest.permission.RECORD_AUDIO
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    //启动音频
                    withAudioEnabled()
                }

            }
            .start(ContextCompat.getMainExecutor(this@CameraXActivity)) { recordEvent ->
                when (recordEvent) {
                    is VideoRecordEvent.Start -> {
                        //录制开始
                        Toast.makeText(this@CameraXActivity, "开始录制", Toast.LENGTH_SHORT)
                            .show()
                    }
                    is VideoRecordEvent.Finalize -> {
                        //录制结束
                        if (!recordEvent.hasError()) {
                            val msg = "Video capture succeeded: " +
                                    "${recordEvent.outputResults.outputUri}"
                            Toast.makeText(this@CameraXActivity, msg, Toast.LENGTH_SHORT)
                                .show()
                            Log.d(TAG, msg)
                        } else {
                            recording?.close()
                            recording = null

                            Log.e(
                                TAG, "Video capture ends with error: " +
                                        "${recordEvent.cause?.message}"


                            )
                        }

                    }
                }
            }
    }

    /**
     * 拍照
     */
    private fun takePhotos() {
        val imageCapture = imageCapture ?: return
        val name = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
            .format(System.currentTimeMillis())
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
            }
        }
        val outputOptions = ImageCapture.OutputFileOptions
            .Builder(
                this@CameraXActivity.contentResolver!!,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                contentValues
            )
            .build()
        imageCapture.takePicture(
            outputOptions,
            ContextCompat.getMainExecutor(this@CameraXActivity),
            object : ImageCapture.OnImageSavedCallback {
                override fun onError(exc: ImageCaptureException) {
                    takePictureStatus(false, exc.message.toString())
                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                }

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val msg = "Photo capture succeeded: ${output.savedUri}"
                    Log.d(TAG, msg)
                    takePictureStatus(true, output.savedUri.toString())
                }
            }
        )
    }

    private fun takePictureStatus(success: Boolean, msg: String) {
        if (success) {
            loaderManager?.restartLoader(1, null, this)
        } else {
            ToastUtils.showLong(msg)
        }
    }

    /**
     * 聚焦
     * @param auto 聚焦模式
     */
    @SuppressLint("RestrictedApi")
    private fun focus(x: Float, y: Float, auto: Boolean) {
        cameraControl?.cancelFocusAndMetering()
        val createPoint: MeteringPoint = if (auto) {
            val meteringPointFactory = DisplayOrientedMeteringPointFactory(
                mDatabind.viewFinder.display!!,
                camera?.cameraInfo!!,
                mDatabind.viewFinder.width?.toFloat()!!,
                mDatabind.viewFinder.height?.toFloat()!!
            )
            meteringPointFactory.createPoint(x, y)
        } else {
            val meteringPointFactory = mDatabind.viewFinder.meteringPointFactory
            meteringPointFactory?.createPoint(x, y)!!
        }


        val build = FocusMeteringAction.Builder(createPoint, FocusMeteringAction.FLAG_AF)
            .setAutoCancelDuration(3, TimeUnit.SECONDS)
            .build()

        val future = cameraControl?.startFocusAndMetering(build)


        future?.addListener({
            try {
                if (future.get().isFocusSuccessful) {
                    //聚焦成功
                    Log.e(TAG, "聚焦成功")
                } else {
                    //聚焦失败
                    Log.e(TAG, "聚焦失败")
                }
            } catch (e: Exception) {
                Log.e(TAG, "异常" + e.message)
            }

        }, ContextCompat.getMainExecutor(this@CameraXActivity))


    }

    /**
     * topView
     * 切换手电筒
     */
    override fun lightCheck() {
        cameraControl?.enableTorch(cameraParams?.torchSwitch!!)
    }

    /**
     * topView
     * 倒计时
     */
    override fun delay() {

    }

    /**
     * topView
     * 闪光灯
     */
    override fun splash() {
        val flashMode =
            if (cameraParams?.mSplashOn == true && cameraParams?.mFacingFront == false) {
                ImageCapture.FLASH_MODE_ON
            } else {
                ImageCapture.FLASH_MODE_OFF
            }

        imageCapture?.flashMode = flashMode
    }

    /**
     * topView
     * 网格线
     */
    override fun grid() {
        mDatabind.GridView.visibility = if (cameraParams?.grid == true) {
            View.VISIBLE
        } else {
            View.GONE
        }
    }

    /**
     * topView
     * hdr
     */
    override fun hdr() {
        openCameraPreView()
    }

    /**
     * topView
     * 分辨率比例
     */
    override fun pickRatio() {
        cameraParams?.mRatioType = when (cameraParams?.mRatioType) {
            CameraRatioType.RATIO_3_4 -> AspectRatio.RATIO_4_3
            CameraRatioType.RATIO_9_16 -> AspectRatio.RATIO_16_9
            CameraRatioType.RATIO_1_1 -> CameraRatioType.RATIO_1_1
            CameraRatioType.RATIO_FULL -> CameraRatioType.RATIO_FULL
            else -> AspectRatio.RATIO_4_3
        }
        openCameraPreView()
        ratioCallBack(cameraParams?.mRatioType)
    }

    /**
     * topView
     * 切换镜头
     */
    override fun backCamera() {
        cameraParams?.mFacingFront = !cameraParams?.mFacingFront!!
        openCameraPreView()
    }

    /**
     * 拍照/录像 按钮
     * 开始录像
     */
    override fun onRecordStart() {
        if (cameraParams?.timer == true) {
            isTakePicture = false
            mDatabind.recordCount.start()
            return
        }
        takeVideo()
    }

    /**
     * 拍照/录像 按钮
     * 结束录像
     */
    override fun onRecordStop() {
        takeVideo()
    }

    /**
     * 拍照/录像 按钮
     * 拍照
     */
    override fun takePhoto() {
        if (cameraParams?.timer == true) {
            isTakePicture = true
            mDatabind.recordCount.start()
            return
        }
        takePhotos()
    }

    override fun onZoom(percent: Float) {

    }

    override fun isClick(): Boolean {
        return true
    }

    /**
     * 倒计时结束
     */
    override fun onCountDownEnd() {
        if (isTakePicture) {
            takePhotos()
        } else {
            takeVideo()
        }
    }

    /**
     * 倒计时取消
     */
    override fun onCountDownCancel() {

    }

    /**
     * 拍照 录像 切换
     */
    override fun onTabSelected(tab: CameraTabView.Tab?) {
        mDatabind.btnRecord.setRecordEnable(tab?.position == 1)
    }

    override fun onTabUnselected(tab: CameraTabView.Tab?) {

    }

    override fun onTabReselected(tab: CameraTabView.Tab?) {

    }

    override fun onCreateLoader(id: Int, args: Bundle?): Loader<Any> {
        return AlbumDataLoader.getImageLoaderWithoutBucketSort(this) as Loader<Any>
    }


    override fun onLoadFinished(loader: Loader<Any>, cursor: Any?) {
        cursor?.let {
            val cursor = it as Cursor
            if (cursor != null && !cursor.isClosed) {
                cursor.moveToFirst()
                val albumData: AlbumData = AlbumData.valueOf(cursor)
                val url = albumData.getCoverUri().toString()
                Log.d(TAG, "the url is $url")
                Glide.with(this@CameraXActivity).load(url)
                    .skipMemoryCache(true)
                    .diskCacheStrategy(DiskCacheStrategy.NONE).into(mDatabind.image)
                cursor.close()
                destroyImageLoader()
            }
        }

    }

    override fun onLoaderReset(loader: Loader<Any>) {

    }

    private fun destroyImageLoader() {
        loaderManager?.destroyLoader(1)

    }

    /**
     * 关闭顶部弹窗
     */
    override fun touchTrans() {
        mDatabind.top.hideRatioPop()
        mDatabind.top.hideSettingPop()
    }


    override fun onDestroy() {
        super.onDestroy()
        destroyImageLoader()
    }


    override fun previewFocus(x: Float, y: Float) {
        focus(x, y, false)
    }

    /**缩放**/
    override fun zoom(out: Boolean) {
        val zoomState = camera?.cameraInfo?.zoomState
        val zoomRatio: Float? = zoomState?.value?.zoomRatio        //当前值
        val maxZoomRatio: Float? = zoomState?.value?.maxZoomRatio//缩放最大值
        val minZoomRatio: Float? = zoomState?.value?.minZoomRatio //缩放最小值
        if (out) {
            //放大
            if (zoomRatio!! < maxZoomRatio!!) {
                cameraControl?.setZoomRatio((zoomRatio + zoomCoefficient))
            }
        } else {
            //缩小
            if (zoomRatio!! > minZoomRatio!!) {
                cameraControl?.setZoomRatio((zoomRatio - zoomCoefficient))
            }
        }
    }

}